<?php

namespace services\rbac;

use api\modules\v1\forms\rbac\ActionForm;
use common\components\Service;
use common\helpers\DateHelper;
use common\helpers\RedisHelper;
use common\models\rbac\Action;
use common\models\rbac\Menu;
use common\models\rbac\RolePermission;
use services\log\LogMemberOpService;
use Yii;

/**
 * Class ActionService
 * @package services\rbac
 */
class ActionService extends Service
{
    /**
     * 动作列表
     * @param array $params
     * @param int $page
     * @param int $pageSize
     * @return array
     */
    public function getListPage(array $params = [], int $page = 0, int $pageSize = 0): array
    {
        $query = Action::find()->alias('a')
            ->select([
                'a.*',
//                'b.name as module_name',
                'm.name menu_name',
            ])
//            ->leftJoin(Module::tableName(). ' AS b', 'a.module_id = b.id')
            ->leftJoin(Menu::tableName(). ' m', 'a.menu_id = m.id');

        if (!isset($params['status'])) {
            $query->where(['a.status' => [Action::STATUS_INVALID, Action::STATUS_ENABLE]]);
        } else {
            $query->where(['a.status' => $params['status']]);
        }

        // 搜索动作名称
        if (isset($params['keyword']) && $params['keyword']) {
            $query->andWhere([
                'or',
                ['like','a.name', $params["keyword"]],
                ['like','a.marking', $params["keyword"]],
                ['like','m.name', $params["keyword"]]
            ]);
        }

        if (isset($params['flag']) && !empty($params['flag'])) {
            $query->andWhere(['a.flag' => $params['flag']]);
        }

        $order = [
            'a.status' => SORT_DESC,
            'a.sort' => SORT_ASC,
            'a.id' => SORT_DESC
        ];

        // 查询结果
        return $this->getListPageRes($query, $page, $pageSize, $order);
    }

    /**
     * 格式化动作列表
     * @param array $data
     * @return array
     */
    public function getListPageFormat(array $data): array
    {
        $list = [];
        foreach ($data as $row) {
            $list[] = [
                'id' => $row['id'],
                'menu_id' => $row['menu_id'],
                'module_id' => $row['module_id'],
                'name' => $row['name'],
                'menu_name' => $row['menu_name'] ?: '',
//                'module_name' => $row['module_name'] ?: '',
                'flag' => $row['flag'],
                'marking' => $row['marking'],
                'sort' => $row['sort'],
                'status' => $row['status'],
                'status_str' => Action::$statuss[$row['status']] ?? '',
                'created_at_str' => DateHelper::timestampToDate($row['created_at']),
            ];
        }
        return $list;
    }

    /**
     * 动作详情
     * @param int $id
     * @return array
     */
    public function getInfo(int $id): array
    {
        $data = [];
        $checkId = 0;
        // 动作信息
        $action = Action::findOne($id);
        if ($action) {
            $data = [
                'id' => $action->id ?? 0,
                'menu_id' => $action->menu_id ?? 0,
                'module_id' => $action->module_id ?? 0,
                'name' => $action->name ?? '',
                'flag' => $action->flag ?? '',
                'marking' => $action->marking ?? '',
                'status' => $action->status ?? Action::STATUS_ENABLE,
                'sort' => $action->sort ?? 0,
            ];
            $checkId = $action->menu_id;
        }

        // 菜单列表
        $menuService = new MenuService();
        $menuList = $menuService->getConditionList($checkId);

        return array_merge($data, [
            'condition' => [
                'menu' => $menuList
            ],
        ]);
    }

    /**
     * 获取全部有效状态动作
     * @return array
     */
    public static function getEnableList(): array
    {
        return Action::find()
            ->where(['status' => Action::STATUS_ENABLE])
            ->orderBy(['sort' => SORT_ASC, 'id' => SORT_ASC])
            ->asArray()
            ->all();
    }

    /**
     * 根据IDs获取全部有效状态菜单
     * @param array $ids
     * @return array
     */
    public static function getEnableListByIds(array $ids): array
    {
        if (empty($ids)) {
            return [];
        }
        return Action::find()
            ->where([
                'id' => $ids,
                'status' => Action::STATUS_ENABLE
            ])
            ->orderBy(['sort' => SORT_ASC, 'id' => SORT_ASC])
            ->asArray()
            ->all();
    }

    /**
     * 根据Ids获取动作列表【禁用 + 正常】
     * @param array $actionIds
     * @return Action[]
     */
    public static function getNormalCacheListByIds(array $actionIds): array
    {
        $data = [];
        foreach ($actionIds as $actionId) {
            $action = RedisHelper::getAction($actionId);
            if (empty($action) || $action->status == Action::STATUS_DELETE) {
                continue;
            }
            $data[] = $action;
        }
        return $data;
    }

    /**
     * 生成flag
     * @param string $route
     * @return string
     */
    public static function createMarking(string $route, int $id): string
    {
        $flag = str_replace('/', '-', trim($route, '/'));
        $query = Action::find()->where(['like', 'marking', $flag]);
        $id && $query->andWhere(['!=', 'id', $id]);
        $count = $query->count();

        if ($count > 0) {
            $flag = $flag.($count + 1);
        }
        return $flag;
    }

    /**
     * 编辑动作
     * @param Action $action
     * @param ActionForm $model
     * @return Action
     * @throws \Exception
     */
    public static function editModel(Action $action, ActionForm $model): Action
    {
//        $action->module_id = $model->module_id;
        $action->menu_id = $model->menu_id;
        $action->name = $model->name;
        $action->flag = trim($model->flag, '/');
        $action->marking = self::createMarking($action->flag, $action->id ?: 0);
        $action->status = $model->status;
        $action->sort = $model->sort;
        $action->saveAndCheckResult();

        return $action;
    }

    /**
     * 新增动作
     * @param ActionForm $model
     * @return array
     * @throws \yii\db\Exception
     */
    public function create(ActionForm $model): array
    {
        try {
            $transaction = Yii::$app->db->beginTransaction();

            // 1.新增动作
            $action = new Action();
            $action = self::editModel($action, $model);

            // 2.日志
            LogMemberOpService::createActionLog($model, $action);

            $transaction->commit();
            return ['id' => $action->id];
        } catch (\Exception $e) {
            $transaction->rollBack();
            throw $e;
        }
    }

    /**
     * 编辑动作
     * @param ActionForm $model
     * @return array
     */
    public function edit(ActionForm $model): array
    {
        try {
            $transaction = Yii::$app->db->beginTransaction();

            // 1.更新动作
            $oldAction = new Action();
            $oldAction->setAttributes($model->getAction()->getAttributes());
            $action = self::editModel($model->getAction(), $model);

            // 2.日志
            LogMemberOpService::createActionLog($model, $action, $oldAction);

            // 3.更新缓存
            RedisHelper::setAction($action);

            $transaction->commit();
            return ['id' => $action->id];
        } catch (\Exception $e) {
            $transaction->rollBack();
            throw $e;
        }
    }

    /**
     * 删除动作
     * @param ActionForm $model
     * @return array
     */
    public function delete(ActionForm $model): array
    {
        try {
            $transaction = Yii::$app->db->beginTransaction();

            // 1.更新动作
            $action = $model->getAction();
            $action->status = Action::STATUS_DELETE;
            $action->saveAndCheckResult();
            // 2.绑定角色人员强制退出登录
            // 绑定动作角色IDs
            $roleIds = array_column(RolePermissionService::getRolePermissionListByPermissionIds(RolePermission::PERMISSION_TYPE_ACTION, $action->id), 'role_id');
            MemberRoleService::clearRoleMemberToken($roleIds);
            // 3.日志
            LogMemberOpService::createActionLog($model, $action);
            // 4.更新缓存
            RedisHelper::setAction($action);

            $transaction->commit();
            return ['id' => $action->id];
        } catch (\Exception $e) {
            $transaction->rollBack();
            throw $e;
        }
    }

    /**
     * 删除菜单绑定动作
     * @param int $menuId
     * @return array
     */
    public static function deleteMenuAction(int $menuId): array
    {
        $actionIds = Action::find()
            ->select(['id'])
            ->where([
                'menu_id' => $menuId,
                'status' => [Action::STATUS_INVALID, Action::STATUS_ENABLE]
            ])
            ->column();
        Action::updateAll(['status' => Action::STATUS_DELETE], ['id' => $actionIds]);

        return $actionIds;
    }
}
